﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using StarsAdmin.Core.App;
using StarsAdmin.Core.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

namespace StarsAdmin.Core.Helpers
{
    public static class JwtHelper
    {
        /// <summary>
        /// 获取Token
        /// </summary>
        /// <param name="id"></param>
        /// <param name="userName"></param>
        /// <param name="version"></param>
        /// <param name="roleIdentify"></param>
        /// <returns></returns>
        public static string GenerateAccessToken(long id, string userName, string version, string[] roleIdentify)
        {
            // 签名算法
            var signingAlgorithm = SecurityAlgorithms.HmacSha256;
            // 秘钥
            var securityKey = AppConfigs.Jwt.SecurityKey;
            // 过期时间
            var expires = DateTime.Now.AddMinutes(AppConfigs.Jwt.Expire);
            //签名证书
            var signingCredentials = new SigningCredentials(securityKey, signingAlgorithm);

            var token = new JwtSecurityToken(
                issuer: AppConfigs.Jwt.Issuer,// 颁发者
                audience: AppConfigs.Jwt.Audience,// 接收者
                claims: SetClaims(id, userName, version, roleIdentify),// 自定义声明
                notBefore: DateTime.Now,
                expires: expires,//过期时间
                signingCredentials: signingCredentials // 签名证书
            );
            JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
            var tokenStr = tokenHandler.WriteToken(token);

            return tokenStr;
        }

        /// <summary>
        /// 获取刷新Token
        /// </summary>
        /// <returns></returns>
        public static string GenerateRefreshToken()
        {
            return StringHelper.GenerateRandom();
        }

        /// <summary>
        /// 获得token
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string GetToken(HttpContext context)
        {
            var authHeader = context.Request.Headers.Authorization.ToString().Split(" ");
            if (authHeader?.Length != 2 || !authHeader[0].Equals("Bearer", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception($"没有有效的Token:{authHeader}");
            }
            return authHeader[1];
        }

        /// <summary>
        /// 获得token
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static string GetToken(ActionExecutingContext context)
        {
            var authHeader = context.HttpContext.Request.Headers["Authorization"].ToString().Split(" ");
            if (authHeader.Length != 2 || !authHeader[0].Equals("Bearer", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception($"没有有效的Token:{authHeader}");
            }
            return authHeader[1];
        }

        /// <summary>
        /// 获得token
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string GetToken(IHttpContextAccessor context)
        {
            var authHeader = context.HttpContext?.Request.Headers.Authorization.ToString().Split(" ");
            if (authHeader?.Length != 2 || !authHeader[0].Equals("Bearer", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception($"没有有效的Token:{authHeader}");
            }
            return authHeader[1];
        }

        /// <summary>
        /// 获得当前用户
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static CurrentUserDto GetCurrentUser(string token)
        {
            try
            {
                // 验证token
                var flag = ValidateAccessToken(token, out ClaimsPrincipal principal, out SecurityToken securityToken);
                if (flag && principal != null)
                {
                    // token存在且principal不为空则获取用户数据
                    var user = principal.FindFirstValue(ClaimTypes.UserData);
                    if (user != null)
                    {
                        var currentUser = JsonConvert.DeserializeObject<CurrentUserDto>(user);
                        return currentUser ?? new CurrentUserDto();
                    }
                }
                return new CurrentUserDto();
            } catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public static long GetUserId(string token)
        {
            try
            {
                // 验证token
                var flag = ValidateAccessToken(token, out ClaimsPrincipal principal, out SecurityToken securityToken);
                if (flag && principal != null)
                {
                    // token存在且principal不为空则获取用户数据
                    var userId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
                    return userId != null ? Math.Abs(long.Parse(userId)) : default;
                }
                return default;
            } catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public static string GetUserName(string token)
        {
            try
            {
                // 验证token
                var flag = ValidateAccessToken(token, out ClaimsPrincipal principal, out SecurityToken securityToken);
                if (flag && principal != null)
                {
                    // token存在且principal不为空则获取用户Name
                    var userName = principal.FindFirstValue(ClaimTypes.Name);
                    return userName ?? string.Empty;
                }
                return string.Empty;
            } catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 获得token版本
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string GetTokenVersion(string token)
        {
            try
            {
                // 验证token
                var flag = ValidateAccessToken(token, out ClaimsPrincipal principal, out SecurityToken securityToken);
                if (flag && principal != null)
                {
                    // token存在且principal不为空则获取token版本数据
                    var version = principal?.FindFirstValue(ClaimTypes.Version);
                    return version ?? string.Empty;
                }
                return string.Empty;
            } catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public static bool ValidateAccessToken(string token, out ClaimsPrincipal principal, out SecurityToken securityToken)
        {
            try
            {
                // 验证参数
                var tokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    RequireExpirationTime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = AppConfigs.Jwt.Issuer,
                    ValidAudience = AppConfigs.Jwt.Audience,
                    IssuerSigningKey = AppConfigs.Jwt.SecurityKey
                };
                JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
                //验证Token
                principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
                if (!(securityToken is JwtSecurityToken jwtSecurityToken) ||
     !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
                {
                    return false;
                }
                return principal != null && securityToken != null;
            } catch (Exception ex)
            {
                principal = null;
                securityToken = null;
                return false;
            }
        }

        /// <summary>
        /// 设置自定义声明信息
        /// </summary>
        /// <param name="currentUser"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        public static IEnumerable<Claim> SetClaims(long id, string userName, string version, string[] roleIdentify)
        {
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.NameIdentifier, id.ToString()),
                new Claim(ClaimTypes.Name, userName),
                new Claim(ClaimTypes.Version,version),
            };
            // 将权限标识添加到声明
            for (int i = 0; i < roleIdentify.Length; i++)
            {
                if (roleIdentify[i] != null)
                {
                    claims.Add(new Claim(ClaimTypes.Role, roleIdentify[i]));
                }
            }
            return claims;
        }
    }
}